//==========================================================================//
//                                                                          //
//  RTCDS1307 Library              Version 0.1                     March 2012  //
//                                                                          //
//  Written for the Arduino Duemilanove w/ ATmega328                        //
//                                                                          //
//  RTCDS1307 Arduino Library                                                  //
//                                                                          //
//  Created by JFLagarde (jeanfrancoislagarde@hotmail.com)                  //
//                                                                          //
//  This file is part of OpenWS (http://code.google.com/p/openws/)          //
//                                                                          //
//==========================================================================//
//                                                                          //
//  Notes:                                                                  //
//                                                                          //
//                                                                          //
//==========================================================================//
//                                                                          //
//  Copyright 2012 Jean-Francois Lagarde (jeanfrancoislagarde@hotmail.com)  //
//  This program is distributed under the terms of                          //
//  the GNU General Public License                                          //
//                                                                          //
//  This program is free software: you can redistribute it and/or modify    //
//  it under the terms of the GNU General Public License as published by    //
//  the Free Software Foundation, either version 3 of the License, or       //
//  (at your option) any later version.                                     //
//                                                                          //
//  This program is distributed in the hope that it will be useful,         //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of          //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           //
//  GNU General Public License for more details.                            //
//                                                                          //
//  You should have received a copy of the GNU General Public License       //
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.   //
//                                                                          //
//==========================================================================//
 
/******************************************************************************
 * Includes
 ******************************************************************************/

#include "RTCDS1307.h"
#include <Wire.h>

/******************************************************************************
 * Definitions
 ******************************************************************************/

#define RTCDS1307_I2C_ADDRESS 0x68  // This is the I2C address

/******************************************************************************
 * Constructors
 ******************************************************************************/

RTCDS1307::RTCDS1307()
{
  Wire.begin();
  //must NOT attempt to read the clock before
  //Wire.begin() has not been called; readClock() will hang.
  //Fortunately, it seems that you can call Wire.begin()
  //multiple times with no adverse effect).
} 

/******************************************************************************
 * User API
 ******************************************************************************/

/***** CHIP READ/WRITE ******/
void RTCDS1307::readClock()
{
  // Reset the register pointer
  Wire.beginTransmission(RTCDS1307_I2C_ADDRESS);
  Wire.write((uint8_t) 0x00);
  Wire.endTransmission();
 
  Wire.requestFrom(RTCDS1307_I2C_ADDRESS, 8);
  _reg0_sec = Wire.read();
  _reg1_min = Wire.read();
  _reg2_hour = Wire.read();
  _reg3_day = Wire.read();
  _reg4_date = Wire.read();
  _reg5_month = Wire.read();
  _reg6_year = Wire.read();
  _reg7_sqw = Wire.read();
}

void RTCDS1307::setClock()
{
  //to be paranoid, we're going to first stop the clock
  //to ensure we don't have rollovers while we're
  //writing:
  writeData(0,0x80);
  //now, we'll write everything *except* the second
  Wire.beginTransmission(RTCDS1307_I2C_ADDRESS);
  Wire.write((uint8_t) 0x01);
  Wire.write(_reg1_min);
  Wire.write(_reg2_hour);
  Wire.write(_reg3_day);
  Wire.write(_reg4_date);
  Wire.write(_reg5_month);
  Wire.write(_reg6_year);
  Wire.endTransmission();
  //now, we'll write the seconds; we didn't have to keep
  //track of whether the clock was already running, because
  //_reg0_sec already knows what we want it to be. This
  //will restart the clock as it writes the new seconds value.
  writeData(0,_reg0_sec); 
}

void RTCDS1307::stop()
{
  //"Bit 7 of register 0 is the clock halt (CH) bit. 
  //When this bit is set to a 1, the oscillator is disabled."
  _reg0_sec = _reg0_sec | 0x80;
  writeData(0,_reg0_sec);
}
void RTCDS1307::start()
{
  //"Bit 7 of register 0 is the clock halt (CH) bit. 
  //When this bit is set to a 1, the oscillator is disabled."
  _reg0_sec = _reg0_sec & ~0x80;
  writeData(0,_reg0_sec);
}

int RTCDS1307::getSeconds()
{
  //need to mask oscillator start/stop bit 7
  return bcdToDec(_reg0_sec & 0x7f);
}
int RTCDS1307::getMinutes()
{
  //could mask with 0x7f but shouldn't need to
  return bcdToDec(_reg1_min);
}
int RTCDS1307::getHours()
{
  //bits 4-5 are tens of hours
  return bcdToDec(_reg2_hour & 0x3f);
}
int RTCDS1307::getDate()
{
  //could mask with 0x3f but shouldn't need to
  return bcdToDec(_reg4_date);
}
int RTCDS1307::getMonth()
{
  //could mask with 0x1f but shouldn't need to
  return bcdToDec(_reg5_month);
}
int RTCDS1307::getYear()
{
  return bcdToDec(_reg6_year);
}


/**** SETTERS *****/
void RTCDS1307::setSeconds(int s)
{
  if (s < 60 && s >=0)
  {
    //need to preserve oscillator bit
    _reg0_sec = decToBcd(s) | (_reg0_sec & 0x80);
  }
}
void RTCDS1307::setMinutes(int m)
{
  if (m < 60 && m >=0)
  {
    _reg1_min = decToBcd(m);
  }
}
void RTCDS1307::setHours(int h)
{
  
    if (h >= 0 && h <=24)
   {
      //preserve 12/24 bit
      _reg2_hour = decToBcd(h) | (_reg2_hour & 0x40);
   }
}//setHours
void RTCDS1307::setDate(int d)
{
  if (d > 0 && d < 32)
  {
    _reg4_date = decToBcd(d);
  }
}
void RTCDS1307::setMonth(int m)
{
  if (m > 0 && m < 13)
  {
    _reg5_month = decToBcd(m);
  }
}
void RTCDS1307::setYear(int y)
{
  if (y >= 0 && y <100)
  {
    _reg6_year = decToBcd(y);
  }
}



/*****************************************
 * Private methods
 *****************************************/
void RTCDS1307::writeData(byte regNo, byte value)
{
  if(regNo > 0x3F) { return; }
   Wire.beginTransmission(RTCDS1307_I2C_ADDRESS);
   Wire.write(regNo);
   Wire.write(value);
   Wire.endTransmission();
}
byte RTCDS1307::decToBcd(byte b)
{
  return ( ((b/10) << 4) + (b%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte RTCDS1307::bcdToDec(byte b)
{
  return ( ((b >> 4)*10) + (b%16) );
}